package service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import models.Offer;
import models.Tag;
import models.User;
import java.util.Comparator;
import com.mchange.v1.util.ArrayUtils;
import javax.persistence.Query;
import play.db.jpa.JPA;
import java.util.Date;

import play.data.validation.*;
import play.mvc.Before;
import play.mvc.Controller;

public class MatchService
{
	
	public static <M extends Matchable> List<M> match(List<M> allItems, String phrase, String coorx, String coory)
    {
	    List<String> tags = Utils.parseTags(phrase);

        List<M> matchedItems = new ArrayList<M>();
        List<M> results = new ArrayList<M>();
        //System.out.println(allItems);
        double[] scoreArray = new double[100];
		long [] indexArray = new long[100];
    	int co = 0;
		int tagCount = 0;
		int foundCount = 0;
		Boolean scoreCalculation = false;
		Date now = new Date();
		
		long MILLSECS_PER_DAY = 1000 * 60 * 60 * 24;  // miliseconds in 1 year
		
        for(M item : allItems) {

        	foundCount = 0;
			tagCount = 0;
			
            double score = 0;
	        double xcoor = item.getCoorX();
	        double ycoor = item.getCoorY();
	        
	        User user = item.getUser();
	        int votepos = user.getPos();
	        int voteneg = user.getNeg();
	        int servicegiv = user.getSgiv();
	        int servicetak = user.getStak();
	        int servtot = servicegiv + servicetak;
			
		
    	Date userRegDate = user.registrationDate;
		
		//Day difference from registration date to today
		long deltaDays = (long)( now.getTime() - userRegDate.getTime() )/ MILLSECS_PER_DAY;
		
		
		//System.out.println("sdasasajdsl:"+deltaDays + ", user:"+user.id+ ",now.getTime(): "+ now.getTime() + ",userRegDate.getTime(): "+userRegDate.getTime() );
	        
			//If user wants to search with coordinate parameters
	        if(coorx != null && coorx.length()>0 && coory != null && coorx.length()>0)
	        {
		        double xdiff = Double.valueOf(coorx)-xcoor;
		        double ydiff = Double.valueOf(coory)-ycoor;
		        double diff = Math.sqrt(Math.pow(xdiff,2)+Math.pow(ydiff,2));
		        
	            
	
	            for(Tag tag : item.getTags()) {
	                for(String tagString : tags) {
	                    if(tag.name.toUpperCase().contains(tagString.toUpperCase())) {
	                    	tagCount++;
	                    }
	                }
	            }
	            scoreCalculation=false;score = 0.66*tagCount-0.25*diff+0.02*(votepos-voteneg)-0.07*Math.log(deltaDays+1);
	        }
			//User does not specify any coordinates via maps, so just check for title, desc and tags
	        else
	        {
			
	            for(Tag tag : item.getTags()) {
	                for(String tagString : tags) {
	                    if(tag.name.toUpperCase().contains(tagString.toUpperCase())) {
	                    	tagCount++;
	                    }
	                }
	            }
	            
				scoreCalculation = true;
	            
	        }


	        String Title = item.getTitle();	 
	        String Desc = item.getDescription();
			
	        /*
			tagString is representing word by word phrase so if user enters a 
			search phrase as: "hello kitty how are you"
			then
			for loop will turn around 5 times
			hello
			kitty
			how
			are
			you
			
			words will be searched in title, description and tag of the item
			*/
	        if(Title!= null && Title.length()>0 && phrase!=null && phrase.length()>0)
	        {
				for(String tagString : tags)
				{
					if(Title.toUpperCase().contains(tagString.toUpperCase()))
					{
						foundCount++;
					}
				}					
	        }
			
	        if(Desc!= null && Desc.length()>0 && phrase!=null && phrase.length()>0)
	        {
				for(String tagString : tags)
				{
					if(Desc.toUpperCase().contains(tagString.toUpperCase()))
					{
						foundCount++;
					}
				}
	        }
			
			if( scoreCalculation )
			{
				int midCount = 0;
				midCount = tagCount + foundCount ;
				score = 0.66*midCount+0.02*(votepos-voteneg)-0.07*Math.log(deltaDays+1);
			}

            if (foundCount > 0 || tagCount > 0 )
			{
            	scoreArray[co] = score;
				indexArray[co] = item.getId();
				
        		matchedItems.add(item);
				co++;
				//System.out.println("co:"+co+"foundCount:"+foundCount+", tagCount:"+tagCount + ", phrase:"+phrase+", Title:"+Title+", Desc:"+Desc);

            }
			
        }
		
		
		/*
		Now we should sort scoreArray and indexArray together
		*/
		double tempScore;
		long tempIndex;
		
		for( int i=0; i<co-1; i++ )
		{
			for( int j=0; j<co-1; j++ )
			{
				if( scoreArray[j] > scoreArray[j+1] )
				{
					//Then swap them
					tempScore = scoreArray[j];
					scoreArray[j] = scoreArray[j+1];
					scoreArray[j+1] = tempScore;
					
					//Then also swap the same position for indexArray
					tempIndex  = indexArray[j];
					indexArray[j] = indexArray[j+1];
					indexArray[j+1] = tempIndex;
				}
			}
		}
		
		
		// Now here we have sorted scoreArray and indexArray which are both sorted as an index param of scoreArray asc. order


        for(int i = 0; i< co; i++)
		{
				/*
				Kutay Ozdogru Fix start for Issue-15
				results should be unique in result list
				*/
				if( !doesExist( results, indexArray[i] ) )
				{
					//If we are here, we are ready to save our unique item to results list
					for( int j=0; j<matchedItems.size(); j++ )
					{
						if( matchedItems.get(j).getId() == indexArray[i] )
						{
							results.add(matchedItems.get(j));
						
							//To avoid multiple results, we break to loop when we first find the item
							break;
						}
					}

				 }
				/*
				Kutay Ozdogru Fix end for Issue-15
				*/
        }
        
        Collections.reverse(results);
  
        return results;
    }
	public static <M extends Matchable> Boolean doesExist(List<M> results, long index)
	{
		
		for( int i=0; i<results.size(); i++ )
		{
			if( results.get(i).getId() == index )
			{
				//If we inserted this index to results array list, then return true
				return true;
			}
		}
		
		//so if we are here, incoming index has not been inserted yet
		return false;
	}
}